#ifndef DETECTION_H
#define DETECTION_H

#include <algorithm>
#include <atomic>
#include <fstream>
#include <iomanip>
#include <map>
#include <random>
#include <sstream>
#include <string>

#include "FastMemcpy.h"
#include "global.h"
#include "hi_buffer.h"
#include "hi_common.h"
#include "hi_common_sys.h"
#include "hi_common_vb.h"
#include "hi_common_video.h"
#include "hi_common_vpss.h"
#include "hi_ivs_md.h"
#include "hi_math.h"
#include "hi_mpi_sys_mem.h"
#include "hi_mpi_vb.h"
#include "hi_mpi_vgs.h"
#include "hi_mpi_vpss.h"
#include "hi_ivs_md.h"
#include "FastMemcpy.h"
#include "global.h"
#include "sat.h"
#include "opencv2/opencv.hpp"
#include "securec.h"
#include "svp_acl.h"
#include "svp_acl_mdl.h"

static const int BYTE_BIT_NUM = 8;  // 1 byte = 8 bit


#define svp_convert_addr_to_ptr(type, addr) ((type *)(hi_uintptr_t)(addr))
#define svp_convert_ptr_to_addr(type, addr) ((type)(hi_uintptr_t)(addr))

class Detection
{
   public:
    Detection(){};
    ~Detection(){};

   public:
    bool Init(std::string mode_path, std::string acl_file_path = "");
    void DumpModelDesc();
    bool detect_uav(const hi_video_frame *frame, std::vector<bbox_t>& bboxes, bool is_yvu = true);
    bool detect_uav_client(const hi_video_frame *frame, std::vector<bbox_t>& bboxes, bool is_yvu = true);
    float PolygonArea(const std::vector<Vector>& vertices);
    std::vector<Vector> ClipPolygon(const std::vector<Vector>& subject, const std::vector<Vector>& clipEdge);
    float PolygonIntersectionArea(const Polygon& norecognize_area_poly, const Polygon& target_poly);
    float CalcPolygonInter(const Polygon& norecognize_area_poly, const Polygon& target_poly);

   private:
    bool InitResource(std::string);
    bool LoadModel(const std::string model_path);
    bool LoadModelFromFileWithMem(const std::string &modelPath);

    bool CreateOutput();
    bool CreateInput();

    bool CreateBuf(int index);
    bool SetDetParas();

    bool CreateInput(void *inputDataBuffer, size_t bufferSize, int stride);
    bool CreateTaskBufAndWorkBuf();
    bool Execute();

    void ProcessPerDectection(size_t detectIdx, std::vector<std::vector<float>> &vaildBox) const;

    bool GetInputStrideParam(int index, size_t &bufSize, size_t &stride, svp_acl_mdl_io_dims &dims);

    void DestroyResource();
    void UnloadModel();

   private:
    int32_t deviceId_{0};
    svp_acl_rt_context context_{nullptr};
    svp_acl_rt_stream stream_{nullptr};

    uint32_t executeNum_{0};

    size_t modelMemSize_{0};
    void *modelMemPtr_{nullptr};
    bool loadFlag_{false};
    uint32_t modelId_{0};
    svp_acl_mdl_desc *modelDesc_{nullptr};
    svp_acl_mdl_dataset *input_{nullptr};
    svp_acl_mdl_dataset *output_{nullptr};
    svp_acl_mdl_io_dims inputDims_{0};
    void *imgBufferData_{nullptr};

    float scoreThr_{0.5};
};

constexpr uint8_t SCALE_SIZE = 3;
constexpr uint8_t CLASS_NUM = 1;    // background and object
constexpr uint8_t OUT_PARM_NUM = 7; /* x, y, w,h, obj , class(2) */

struct DetectionInnerParam
{
    float *outData{nullptr};
    size_t detectIdx{0};
    size_t wStrideOffset{0};
    float scoreThr{0.0f};
    uint32_t outWidth{0};
    uint32_t chnStep{0};
    uint32_t outHeightIdx{0};
    uint32_t objScoreOffset{0};
};

class Utils
{
   public:
    /**
     * @brief create device buffer of file
     * @param [in] fileName: file name
     * @param [out] fileSize: size of file
     * @return device buffer of file
     */
    static void *GetDeviceBufferOfFile(const std::string &fileName, const svp_acl_mdl_io_dims &dims,
                                       size_t stride, size_t dataSize);

    /**
     * @brief create buffer of file
     * @param [in] fileName: file name
     * @param [out] fileSize: size of file
     * @return buffer of pic
     */
    static void *ReadBinFile(const std::string &fileName, uint32_t &fileSize);

    static bool ReadFloatFile(const std::string &fileName, std::vector<float> &detParas);

    static bool GetFileSize(const std::string &fileName, uint32_t &fileSize);

    static void *ReadBinFileWithStride(const std::string &fileName, const svp_acl_mdl_io_dims &dims,
                                       size_t stride, size_t dataSize);

    static void InitData(int8_t *data, size_t dataSize);
};

#endif
